import 'package:dio/dio.dart';
import 'app_exceptions.dart';
import 'app_response.dart';
import 'dio_config.dart';

class DioClient {
  static final DioConfig _dioConfig = DioConfig.of();

  static final Dio _dio = Dio(
    BaseOptions(
      baseUrl: _dioConfig.baseUrl,
      contentType: 'application/json',
      connectTimeout: 5000,
      receiveTimeout: 3000,
    ),
  )..interceptors.addAll(_dioConfig.interceptors!);

  // get
  Future<AppResponse> get(
    String uri, {
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onReceiveProgress,
  }) async {
    try {
      var response = await _dio.get<dynamic>(
        uri,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
        onReceiveProgress: onReceiveProgress,
      );
      return AppResponse.obtain(response);
    } on Exception catch (e) {
      throw AppException.obtainFromException(e);
    }
  }

  // post
  Future<AppResponse> post(
    String uri, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
  }) async {
    try {
      var response = await _dio.post<dynamic>(
        uri,
        data: data,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
        onSendProgress: onSendProgress,
        onReceiveProgress: onReceiveProgress,
      );
      return AppResponse.obtain(response);
    } on Exception catch (e) {
      throw AppException.obtainFromException(e);
    }
  }

  // patch
  Future<AppResponse> patch(
    String uri, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
  }) async {
    try {
      var response = await _dio.patch<dynamic>(
        uri,
        data: data,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
        onSendProgress: onSendProgress,
        onReceiveProgress: onReceiveProgress,
      );
      return AppResponse.obtain(response);
    } on Exception catch (e) {
      throw AppException.obtainFromException(e);
    }
  }

  // delete
  Future<AppResponse> delete(
    String uri, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
  }) async {
    try {
      var response = await _dio.delete<dynamic>(
        uri,
        data: data,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
      );
      return AppResponse.obtain(response);
    } on FormatException catch (_) {
      throw FormatException('Unable to process the data');
    } on Exception catch (e) {
      throw AppException.obtainFromException(e);
    }
  }

  // put
  Future<AppResponse> put(
    String uri, {
    dynamic data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
  }) async {
    try {
      var response = await _dio.put<dynamic>(
        uri,
        data: data,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken,
      );
      return AppResponse.obtain(response);
    } on Exception catch (e) {
      throw AppException.obtainFromException(e);
    }
  }
}
